
package com.lzx.iteam.contactssearch.conversion;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.text.TextUtils;
import android.util.Log;
import com.lzx.iteam.DialerApp;
import com.lzx.iteam.contactssearch.ContactsDBReader;
import com.lzx.iteam.engine.observer.FreshContactObserver;
import com.lzx.iteam.net.LocalLogin;
import com.lzx.iteam.util.Constants;
import com.lzx.iteam.util.PhoneNumberArea;
import com.lzx.iteam.util.PreferenceUtil;
import com.lzx.iteam.util.StringUtil;
import com.lzx.iteam.contactssearch.conversion.Addressbook.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;

public class PersistWorker {
    private static final String TAG = "PersistWorker";

    private ContentResolver mResolver;

    private Context mContext;

    private PinyinSearch mPinyinSearch;

    private PreferenceUtil mPreferenceUtil = null;

    private DialerApp mDialerApp;

    public boolean mServiceStartup = false;
    // use to update the other module about the change of contact
    private HashSet<String> mContactDelete;
    private HashSet<Long> mContactInsert;
    private HashSet<Long> mContactUpdate;
    private static PersistWorker mPersistWorker;
    public boolean isRunning = false;
    private StringBuffer wx_ids = new StringBuffer();


    private PersistWorker(Context context) {
        this.mResolver = context.getContentResolver();
        mContext = context;
        mDialerApp = (DialerApp) context.getApplicationContext();

        mPreferenceUtil = PreferenceUtil.getInstance(context);
        mPinyinSearch = PinyinSearch.getInstance(context);

    }

    public static PersistWorker getInstance(Context context){
        synchronized (Constants.InstanceLock){
            if(mPersistWorker == null){
                return new PersistWorker(context);
            }
        }
        return mPersistWorker;
    }

    private Cursor queryContacts() {
        boolean ifShowPeopleNoPhone = mPreferenceUtil.getBoolean(PreferenceUtil.SHOW_PEOPLE_NO_PHONENUMBER, false);
        return mResolver.query(Contacts.CONTENT_URI, ContactsDBReader.CONTACTS_SUMMARY_PROJECTION,
                ifShowPeopleNoPhone ? null : Constants.CLAUSE_ONLY_PHONES, null, null);
    }

    /**
     * Get a changed contacts list.
     *
     * @return
     */
    public final void getChangesList(boolean serviceStartup) {

        synchronized (Constants.persisWorkerlock){
            Cursor contacts = null;
            isRunning = true;
            mServiceStartup = serviceStartup;
            contacts = queryContacts();

            if (contacts == null || contacts.getCount() <= 0) {
                if (contacts != null) {
                    contacts.close();
                }
                return;
            }

            if (LocalLogin.getInstance().isLogedin()) {
                mContactInsert = new HashSet<Long>();
                mContactUpdate = new HashSet<Long>();
                mContactDelete = new HashSet<String>();
            }

            long start = 0L;
            if (Constants.DEBUG) Log.d(TAG, "getChangesList begin: "
                    + (start = System.currentTimeMillis()));

            ContactsDBReader.ALL_CONTACTS_NUMBER = contacts.getCount();
            generatePinyinIndex(contacts);
            generateFuzzyIndex(contacts, mContactInsert, mContactUpdate, mContactDelete);
            if (mContactInsert != null && mContactInsert.size() > 0) {
                StringBuilder sb = new StringBuilder();
                Iterator<Long> iterator = mContactInsert.iterator();
                while (iterator.hasNext()) {
                    sb.append(iterator.next()).append('|');
                }

                mPreferenceUtil.save(PreferenceUtil.CONTACT_INSERT, sb.toString());
            }

            if (mContactUpdate != null && mContactUpdate.size() > 0) {
                StringBuilder sb = new StringBuilder();
                Iterator<Long> iterator = mContactUpdate.iterator();
                while (iterator.hasNext()) {
                    sb.append(iterator.next()).append('|');
                }
                mPreferenceUtil.save(PreferenceUtil.CONTACT_UPDATE, sb.toString());

                //: NameCardChange module -- need refactor ?
                long nameCardId = mPreferenceUtil.getLong(PreferenceUtil.NAMECARD_CONTACTID, -1);
                if (mContactUpdate.contains(nameCardId)) {
                    mPreferenceUtil.save(PreferenceUtil.NAMECARD_CHANGED, true);
                }
            }

            if (mContactDelete != null && mContactDelete.size() > 0) {
                StringBuilder sb = new StringBuilder();
                Iterator<String> iterator = mContactDelete.iterator();
                while (iterator.hasNext()) {
                    sb.append(iterator.next()).append('|');
                }
                mPreferenceUtil.save(PreferenceUtil.CONTACT_DELETE, sb.toString());
            }

            if (Constants.DEBUG) Log.d(TAG, "getChangesList end: "
                    + (System.currentTimeMillis() - start));
            Log.d("FreshContactObserver", "value: persistwork");
            contacts.close();
            Intent intent = new Intent("broadcast_status_change");
            mContext.sendBroadcast(intent);
            isRunning = false;
            FreshContactObserver.ENTRANCE_ONECE = false;

        }


    }

    public boolean isRun(){
        return isRunning;
    }

    //do contactname index only 
    private void generatePinyinIndex(Cursor contacts) {
        if (contacts == null) {
            return;
        }

        contacts.moveToPosition(-1);
//        mPinyinSearch.clearMemoryData();
        if (mPinyinSearch.mHanziPinyin == null) {
            mPinyinSearch.mHanziPinyin = StringUtil.getHanziPinyin(mContext, null);
        }
        while (contacts.moveToNext()) {
            if (PinyinSearch.mPersistInterrupted) {
                return;
            }

            long contactId = contacts.getLong(ContactsDBReader.SUMMARY_ID_COLUMN_INDEX);
            String displayName = contacts.getString(ContactsDBReader.SUMMARY_NAME_COLUMN_INDEX);
            int contactedNumber = contacts.getInt(ContactsDBReader.SUMMARY_TIMES_CONTACTED_COLUMN_INDEX);
            int hasPhoneNumber = contacts.getInt(ContactsDBReader.SUMMARY_HAS_PHONE_COLUMN_INDEX);

            if (hasPhoneNumber == 1) {
                if (StringUtil.isEmpty(displayName)) {
                    displayName = mContext.getString(com.lzx.iteam.R.string.unknown);
                }
                mPinyinSearch.addPinyinDict(displayName, contactId, null, contactedNumber, hasPhoneNumber == 1 ? true : false);
            } else {
                if (ContactsDBReader.checkContactNameExistByID(mResolver, contactId)) {
                    mPinyinSearch.addPinyinDict(displayName, contactId, null, contactedNumber, hasPhoneNumber == 1 ? true : false);
                }
            }
        }
        mPinyinSearch.mHanziPinyin = null;
    }

    static HashSet<String> currentContactIds = new HashSet<String>();
    static ArrayList<String> phoneNumArr = new ArrayList<String>();
    static ArrayList<String> phoneNumberAreaArr = new ArrayList<String>();
    static HashSet<String> groupIdSet = new HashSet<String>();
    static StringBuilder orgnization = new StringBuilder();
    static StringBuilder emailString = new StringBuilder();
    static StringBuilder noteString = new StringBuilder();
    static StringBuilder wxFlag = new StringBuilder();

    private void generateFuzzyIndex(Cursor contacts, HashSet<Long> contactInsert, HashSet<Long> contactUpdate,
                                    HashSet<String> contactDelete) {
        //all contactIds have been persisted
        HashSet<String> persistedContactId = (HashSet<String>) mPreferenceUtil.getObject(PreferenceUtil.PERSISTED_CONTACT_ID);
        HashSet<String> contactIdToDel = null;
        currentContactIds.clear();


        if (PinyinSearch.mPersistInterrupted) {
//            mPinyinSearch.mStringHashPool.returnObj(currentContactIds);
            return;
        }
        if (mPinyinSearch.mFirstLetterStr == null) {
            mPinyinSearch.mFirstLetterStr = StringUtil.getFirstLetterStr(mContext);
        }
        contacts.moveToPosition(-1);
        boolean needSave = false;
        //delete by lk for test
        while (contacts.moveToNext()) {
            if (PinyinSearch.mPersistInterrupted) {
                if (needSave) {
                    mPreferenceUtil.saveObject(PreferenceUtil.PERSISTED_CONTACT_ID,
                            currentContactIds);
                }
                return;
            }

            String fullName = null;
            String organizationName = null;
            String email = null;
            String note = null;
            phoneNumArr.clear();
            phoneNumberAreaArr.clear();
            groupIdSet.clear();
            emailString.setLength(0);
            orgnization.setLength(0);
            noteString.setLength(0);

            long contactId = 0L;
            long rawId = 0L;
            long photoId = 0L;
            long version = 0L;
            int type = 0;

            fullName = contacts.getString(ContactsDBReader.SUMMARY_NAME_COLUMN_INDEX);
            contactId = contacts.getLong(ContactsDBReader.SUMMARY_ID_COLUMN_INDEX);
            photoId = contacts.getLong(ContactsDBReader.SUMMARY_PHOTO_ID_COLUMN_INDEX);
            int hasPhoneNumber = contacts.getInt(ContactsDBReader.SUMMARY_HAS_PHONE_COLUMN_INDEX);

            if (hasPhoneNumber == 0) {
                if (!ContactsDBReader.checkContactNameExistByID(mResolver, contactId)) {
                    continue;
                }
            }

            if (StringUtil.isEmpty(fullName)) {
                fullName = mContext.getString(com.lzx.iteam.R.string.unknown);
            }
            long[] ret = ContactsDBReader.getRawContactIdAndVersion(mResolver, contactId);
            rawId = ret[0];
            version = ret[1];

            // the contact has been persisted
            if (persistedContactId != null && persistedContactId.contains(Long.toString(contactId))) {
                Addressbook.Person person = mPreferenceUtil.getPerson(contactId);
                if (person != null) {
                    persistedContactId.remove(Long.toString(contactId));
                    if (person.getVersion() != version) {
                        type = Constants.TYPE_UPDATE;
                    } else {
                        type = Constants.TYPE_EQUAL;
                        if (!mServiceStartup) {
//                            Log.i(TAG, "already exist");
                            currentContactIds.add(Long.toString(contactId));
                            continue;
                        }
                    }
                } else {
                    needSave = true;
//                    Log.i(TAG, "already exist");
                    type = Constants.TYPE_INSERT;
                }
            } else {
                needSave = true;
//                Log.i(TAG, "does not exist in persist, index:" + index);
                type = Constants.TYPE_INSERT;
            }
            currentContactIds.add(Long.toString(contactId));
            Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
            String dataDir = Contacts.Data.CONTENT_DIRECTORY;
            Uri methodUri = Uri.withAppendedPath(contactUri, dataDir);

            Cursor c = null;
            try {
                c = mContext.getContentResolver().query(methodUri,
                        ContactsDBReader.DATA_PROJECTION, null, null, null);
            } catch (IllegalArgumentException e) {
                if (c != null) {
                    c.close();
                }
                continue;
            }

            if (c != null) {
                try {
                    boolean isTrue = c.moveToFirst();
                    while (isTrue) {
                        String mime = c.getString(c.getColumnIndex(Data.MIMETYPE));
                        if (Phone.CONTENT_ITEM_TYPE.equals(mime)) {
                            String phoneNumber = c.getString(c.getColumnIndex(Phone.NUMBER));
                            phoneNumArr.add(phoneNumber);
                            /*PhoneNumberArea phoneNumberArea = PhoneNumberArea.getInstance(mContext.getApplicationContext());
                            String area = phoneNumberArea.getArea(phoneNumber,
                                    false);
                            if (!StringUtil.isEmpty(area)) {
                                if (!phoneNumberAreaArr.contains(area)) {
                                    phoneNumberAreaArr.add(area);
                                }
                            }*/
                        } else if (GroupMembership.CONTENT_ITEM_TYPE.equals(mime)) {
                            String groupId = c.getString(c
                                    .getColumnIndex(GroupMembership.GROUP_ROW_ID));
                            if (groupId != null && ContactsDBReader.mGroupList != null) {
                                ContactsDBReader.GroupInfo group = ContactsDBReader.mGroupList.get(groupId);
                                if (group != null) {
                                    groupIdSet.add(groupId);
                                }
                            }

                        } else if (CommonDataKinds.Email.CONTENT_ITEM_TYPE.equals(mime)) {
                            emailString.append(email);
                            emailString.append(",");

                        } else if (CommonDataKinds.Organization.CONTENT_ITEM_TYPE.equals(mime)) {
                            String company = c.getString(c
                                    .getColumnIndex(CommonDataKinds.Organization.COMPANY));// item.getPrimaryData();
                            String post = c.getString(c
                                    .getColumnIndex(CommonDataKinds.Organization.TITLE));// item.getPrimaryData();
                            if (!StringUtil.isEmpty(post)) {
                                orgnization.append(post);
                            }
                            if (!StringUtil.isEmpty(company)) {
                                if (orgnization.length() > 0) {
                                    orgnization.append(",");
                                }
                                orgnization.append(" " + company);
                            }
                        } else if (CommonDataKinds.Note.CONTENT_ITEM_TYPE.equals(mime)) {
                            noteString.append(c.getString(c.getColumnIndex(
                                    CommonDataKinds.Note.NOTE))).append(',');
                        }else if(Constants.WX_CHAT.equals(mime)){
                            String wx_tag = c.getString(c.getColumnIndex(Data.DATA2));
                            String wx_type = c.getString(c.getColumnIndex(Data.DATA3));
                            if ("微信".equals(wx_tag) && (("发送消息".equals(wx_type)) || ("聊天".equals(wx_type)))) {
                                wx_ids.append(""+contactId);
                                wx_ids.append(",");
                            }
                        }
                        isTrue = c.moveToNext();
                    }

                }  catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    c.close();
                }

            }

            /*******************************************************************/
            if (orgnization != null) {
                organizationName = orgnization.toString();
            }

            if (emailString != null) {
                email = emailString.toString();
            }

            StringBuilder fuzzyStringSb = new StringBuilder();
            if (phoneNumberAreaArr != null) {
                for (String areaElement : phoneNumberAreaArr) {
                    if (!StringUtil.isEmpty(areaElement)) {
                        fuzzyStringSb.append(StringUtil.trasferDisplayName(mContext,
                                new StringBuffer(areaElement), mPinyinSearch.mFirstLetterStr));
                        fuzzyStringSb.append(",");
                    }
                }
            }
            if (!StringUtil.isEmpty(fullName)) {
                StringBuffer sb = new StringBuffer(fullName);
                fuzzyStringSb.append(StringUtil.trasferDisplayName(mContext, sb,
                        mPinyinSearch.mFirstLetterStr));
                fuzzyStringSb.append(",");
            }

            if (!StringUtil.isEmpty(organizationName)) {
                StringBuffer sb = new StringBuffer(organizationName);
                fuzzyStringSb.append(StringUtil.trasferGOJ(mContext, sb,
                        mPinyinSearch.mFirstLetterStr));
            }

            if (phoneNumberAreaArr != null) {
                for (String areaElement : phoneNumberAreaArr) {
                    String fuzzyArea = StringUtil.trasferDisplayName(mContext,
                            new StringBuffer(areaElement), mPinyinSearch.mFirstLetterStr);
                    fuzzyArea += ",";
                    fuzzyStringSb.insert(0, fuzzyArea);
                }
            }

            if (noteString != null) {
                note = noteString.toString();
            }

            if (!TextUtils.isEmpty(note)) {
                fuzzyStringSb.append(StringUtil.trasferDisplayName(mContext,
                        new StringBuffer(note),
                        mPinyinSearch.mFirstLetterStr));
            }

//            String fuzzy = StringUtil.trim(fuzzyStringSb.toString());
            String fuzzy = fuzzyStringSb.toString().replaceAll(StringUtil.SAPCE_REGEX, "");
            mPinyinSearch.addFuzzyString(contactId, fuzzy);

            if (type == Constants.TYPE_INSERT && contactInsert != null) {
                contactInsert.add(contactId);
            } else if (type == Constants.TYPE_UPDATE && contactUpdate != null) {
                contactUpdate.add(contactId);
            }

            if (type != Constants.TYPE_EQUAL) {
//                Log.i(TAG, "need insert, index:" + (index++));
                Person.Builder builder = Addressbook.Person.newBuilder();

                builder.setDisplayName(fullName);
                builder.setPhotoId(photoId);
                builder.setRawId(rawId);
                if (organizationName == null) {
                    organizationName = "";
                }
                builder.setOrganization(organizationName);

                if (email == null) {
                    email = "";
                }
                builder.setEmail(email);
                builder.setFuzzyString(fuzzy);
                builder.setContactedNumber(0);
                builder.setVersion(version);
                builder.setNote(note);

                if (phoneNumArr != null) {
                    for (String phoneElement : phoneNumArr) {
                        if (!StringUtil.isEmpty(phoneElement)) {
                            builder.addPhone(Person.PhoneNumber.newBuilder()
                                    .setNumber(phoneElement));
                        }
                    }
                }

                if (phoneNumberAreaArr != null) {
                    for (String areaElement : phoneNumberAreaArr) {
                        if (!StringUtil.isEmpty(areaElement)) {
                            builder.addPhoneNumberArea(Person.PhoneNumberArea.newBuilder().setArea(
                                    areaElement));
                        }
                    }
                }

                if (groupIdSet != null) {
                    Iterator<String> it = groupIdSet.iterator();
                    while (it.hasNext()) {
                        String groupId = it.next();
                        builder.addGroupIdSet(Person.GroupIdSet.newBuilder().setGroupId(
                                Long.parseLong(groupId)));
                    }
                }
                Person person = builder.build();

                mPreferenceUtil.deletePerson(contactId);
                mPreferenceUtil.savePerson(contactId, person);
            }
        }

        if (persistedContactId != null && contactDelete != null) {
            contactDelete.addAll(persistedContactId);
        }

        contactIdToDel = persistedContactId;
        if (contactIdToDel != null && contactIdToDel.size() > 0) {
            Iterator<String> it = contactIdToDel.iterator();
            mPinyinSearch.mHanziPinyin = StringUtil.getHanziPinyin(mContext, null);
            while (it.hasNext()) {

                if (PinyinSearch.mPersistInterrupted) {
                    if (needSave) {
                        mPreferenceUtil.saveObject(PreferenceUtil.PERSISTED_CONTACT_ID, currentContactIds);
                    }
                    return;
                }
                String contactId = it.next();
                Person person = mPreferenceUtil.getPerson(contactId);
                String displayName = null;
                if (person != null) {
                    displayName = person.getDisplayName();
                }

                mPinyinSearch.delPinyinDict(displayName, Long.parseLong(contactId));
                mPreferenceUtil.deletePerson(contactId);
                mPinyinSearch.getContactInfo().remove(contactId);
            }
            mPinyinSearch.mHanziPinyin = null;
        }

        mPinyinSearch.mFirstLetterStr = null;
        if (needSave) {
//            Log.i(TAG, "save contactId size:" + currentContactIds.size());
            mPreferenceUtil.saveObject(PreferenceUtil.PERSISTED_CONTACT_ID, currentContactIds);
        }
       /* if(wx_ids != null && wx_ids.length() > 0){
            wx_ids.deleteCharAt(wx_ids.length() - 1);
        }*/
        if(StringUtil.isEmpty(wx_ids.toString())){
            mPreferenceUtil.delete(Constants.WX_IDS_SET);
        }else{
            String format_wx_ids = ","+wx_ids.toString();
            mPreferenceUtil.save(Constants.WX_IDS_SET,format_wx_ids);
        }
    }

}
